#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"

class TcpServer;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,
    ACCEPT_ERROR

};

struct ClientDate
{
public:
    std::string ip_;
    uint16_t port_;
    int socketfd_;
    TcpServer *tcpServer;
};

const uint16_t deafaultPort = 8080;
const std::string deafaultIp = "0.0.0.0";
const int backlog = 10;
const int maxThreadNumber = 5;

class TcpServer
{
public:
    TcpServer(const uint16_t &port = deafaultPort, const std::string &ip = deafaultIp) : port_(port),
                                                                                         ip_(ip)
    {
    }

    ~TcpServer()
    {
    }

    void InIt()
    {
        // 创建一个通讯？
        socketfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (socketfd_ < 0)
        {
            lg.logmessage(Fatal, "socket error errno:%d strerror:%s", errno, strerror(errno));
            exit(SOCKET_ERROR);
        }
        lg.logmessage(Info, "socket success socekfd:%d", socketfd_);
        // 绑定一个端口
        // 创建一个描述这个套接字的结构体并相应赋值
        sockaddr_in server_in;
        bzero(&server_in, sizeof(server_in));
        inet_aton(ip_.c_str(), &server_in.sin_addr);
        server_in.sin_family = AF_INET;
        server_in.sin_port = htons(port_);
        socklen_t len = sizeof(server_in);
        // 赋值完成
        if (bind(socketfd_, (sockaddr *)&server_in, len) < 0)
        {
            lg.logmessage(Fatal, "bind error errno:%d strerror:%s", errno, strerror(errno));
            exit(BIND_ERROR);
        }
        lg.logmessage(Info, "bind success");
        // 绑定端口完成

        // 监听
        if (listen(socketfd_, backlog) < 0)
        {
            lg.logmessage(Fatal, "listen error errno:%d strerror:%s", errno, strerror(errno));
            exit(LISTEN_ERROR);
        }
        lg.logmessage(Info, "listen success");
        // 监听完成
    }

    // void Run()
    //{
    /// 单进程板
    // while (1)
    // {
    //     sockaddr_in client;
    //     bzero(&client, sizeof(client));
    //     socklen_t len = sizeof(client);
    //     int client_socketfd;
    //     if ((client_socketfd = accept(socketfd_, (sockaddr *)&client, &len)) < 0)
    //     {
    //     }
    //     lg.logmessage(Info, "Add a new client [%s:%d] client_socketfd:%d ", inet_ntoa(client.sin_addr), ntohs(client.sin_port), client_socketfd);
    //     char arr[1024 * 1024];
    //     while (1)
    //     {
    //         int n = read(client_socketfd, arr, sizeof(arr));
    //         if (n == 0)
    //         {
    //             lg.logmessage(Info, "client [%s:%d] is quit", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
    //             close(client_socketfd);
    //             break;
    //         }
    //         if (n < 0)
    //         {
    //             lg.logmessage(Fatal, "read error errno:%d strerror:%s", errno, strerror(errno));
    //             exit(READ_ERROR);
    //         }
    //         arr[n] = 0;
    //         lg.logmessage(Info, "client say @%s", arr);
    //     }
    // }

    // 多线程板
    //     while (1)
    //     {
    //         sockaddr_in client;
    //         bzero(&client, sizeof(client));
    //         socklen_t len = sizeof(client);
    //         int client_socketfd;
    //         if ((client_socketfd = accept(socketfd_, (sockaddr *)&client, &len)) < 0)
    //         {
    //             lg.logmessage(Fatal, "accept error errno:%d strerror:%s", errno, strerror(errno));
    //             exit(ACCEPT_ERROR);
    //         }
    //         std::string clientIp = inet_ntoa(client.sin_addr);
    //         uint16_t clientPort = ntohs(client.sin_port);
    //         lg.logmessage(Info, "Add a new client [%s:%d] client_socketfd:%d ", clientIp.c_str(), clientPort, client_socketfd);
    //         ClientDate *clientDate = new ClientDate();
    //         clientDate->ip_ = clientIp;
    //         clientDate->port_ = clientPort;
    //         clientDate->socketfd_ = client_socketfd;
    //         clientDate->tcpServer = this;
    //         pthread_t clientPthread;
    //         pthread_create(&clientPthread, nullptr, Servers, (void *)clientDate);
    //     }
    // }

    // static void *Servers(void *argvs)
    // {
    //     ClientDate *clientDate = static_cast<ClientDate *>(argvs);
    //     char arr[1024 * 1024];
    //     while (1)
    //     {
    //         int read_ret = read(clientDate->socketfd_, arr, sizeof(arr));
    //         if (read_ret == 0)
    //         {
    //             QuitClient(clientDate);
    //             return 0;
    //         }
    //         else if (read_ret < 0)
    //         {
    //             lg.logmessage(Warning, "read waring errno:%d strerror:%s", errno, strerror(errno));
    //              QuitClient(clientDate);
    //             return 0;
    //         }
    //         arr[read_ret] = 0;
    //         lg.logmessage(Info, "client[%s:%d] say: %s", clientDate->ip_.c_str(), clientDate->port_, arr);
    //         std::string echo_str = "server say:";
    //         echo_str.append(arr);
    //         int write_ret = write(clientDate->socketfd_, echo_str.c_str(), echo_str.size());
    //         if (write_ret < 0)
    //         {
    //             lg.logmessage(Warning, "write warning errno:%d strerror:%s", errno, strerror((errno)));
    //             QuitClient(clientDate);
    //             return 0;
    //         }
    //     }
    // }

    // 线程池板
    void Run()
    {
        // 创建线程池
        ThreadPool<Task>::GetInstance(maxThreadNumber)->Start();
        // 创建结束

        // 接收客户端
        while (1)
        {
            sockaddr_in client;
            socklen_t len = sizeof(client);
            bzero(&client, len);
            int client_socketfd = accept(socketfd_, (sockaddr *)&client, &len);
            if (client_socketfd < 0)
            {
                lg.logmessage(Warning, "accept error errno:%d strerror:%s", errno, strerror(errno));
                continue;
            }
            std::string clientIp = inet_ntoa(client.sin_addr);
            uint16_t clientPort = ntohs(client.sin_port);
            lg.logmessage(Info, "Add a new client [%s:%d] client_socketfd:%d ", clientIp.c_str(), clientPort, client_socketfd);
            // 接收结束

            ClientDate *clientDate = new ClientDate();
            clientDate->ip_ = clientIp;
            clientDate->port_ = clientPort;
            clientDate->socketfd_ = client_socketfd;
            clientDate->tcpServer = this;
            Task task;
            task.func = &Server;
            task.argc = (void*)clientDate;
            ThreadPool<Task>::GetInstance()->Push(task);
        }
    }

    static void *Server(void *argvs)
    {
        std::cout<<"debug... 1"<<std::endl;
        ClientDate *clientDate = static_cast<ClientDate *>(argvs);
         std::cout<<"debug... 3 socketfd:"<<clientDate->socketfd_<<std::endl;
        char arr[1024 * 1024];
        int read_ret = read(clientDate->socketfd_, arr, sizeof(arr));
        std::cout<<"debug... 2"<<std::endl;
        if (read_ret == 0)
        {
            QuitClient(clientDate);
            return 0;
        }
        else if (read_ret < 0)
        {
            lg.logmessage(Fatal, "read error errno:%d strerror:%s", errno, strerror(errno));
            QuitClient(clientDate);
            return 0;
        }
        arr[read_ret] = 0;
        lg.logmessage(Info, "client[%s:%d] say: %s", clientDate->ip_.c_str(), clientDate->port_, arr);
        std::string echo_str = "server say:";
        echo_str.append(arr);
        int write_ret = write(clientDate->socketfd_, echo_str.c_str(), echo_str.size());
        if (write_ret < 0)
        {
            lg.logmessage(Warning, "write warning errno:%d strerror:%s", errno, strerror((errno)));
            QuitClient(clientDate);
            return 0;
        }
        QuitClient(clientDate);
    }

    static void QuitClient(ClientDate *clientDate)
    {

        close(clientDate->socketfd_);
        lg.logmessage(Info, "client [%s:%d] is quit", clientDate->ip_.c_str(), clientDate->port_);
        delete clientDate;
        clientDate = nullptr;
    }

private:
    int socketfd_;
    std::string ip_;
    uint16_t port_;
};